package com.google.code.jmarias.server.tcp;

import com.google.code.jmarias.common.action.AbstractAction;
import com.google.code.jmarias.common.action.ConnectRoomAction;
import com.google.code.jmarias.common.action.CreateRoomAction;
import com.google.code.jmarias.common.action.GameAction;
import com.google.code.jmarias.common.action.RoomListEcho;
import com.google.code.jmarias.common.action.SignedAction;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Stavovy automat pro komunikaci s klientem. Ke kazdemu klientovi se udrzuje jeho
 * stav v podobe instance teto tridy.
 *
 * Neni thread-safe. Ten, kdo pracuje s touto tridou, musi zajistit, aby pozadavky
 * chodily za sebou, tzn. nesmi s touto tridou primo pracovat jednotliva vlakna
 * klientu.
 * @TODO je potreba zajistit i to, aby nedoslo k soubeznemu behu vice instanci teto
 * tridy (pokud bude hrat vice hracu soucasne), protoze instance teto tridy sdili
 * s ostatnimi v mistnosti Room a Game. Zda se ale, ze i tato podminka je splnena
 *
 *
 * @author Ondrej Michal
 */
public class ServerProtocol {

    private static Log log = LogFactory.getLog(ServerProtocol.class);

    private static enum ClientState {incoming, online, inRoom, sitting, playing}

    //private ClientState state = ClientState.incoming;
    private ClientState state = ClientState.online; // @TODO pouze pro testovani

    private AbstractContactableUser client;

    private Casino casino;

    private Room currentRoom;

//    private boolean finalState = false;
//
//

    public ServerProtocol(Casino casino, AbstractContactableUser client) {
        this.casino = casino;
        this.client = client;
    }

    public void processActionFromClient(SignedAction action) {
        AbstractAction rawAction = action.getRawAction();
        if (state.equals(ClientState.incoming)) {
            // Prvni akci (prihlaseni) odchyti tady. Teprve pokud je prihlaseni v poradku
            // vytvori instanci RemoteClient a dalsi akce zpracovava tam
//            LoginAction loginAction = (LoginAction) action;

            // @TODO kontrolovat, jestli uz stejny uzivatel neni prihlasen z jineho klienta

//            Player p = casino.getRegisteredPlayers().get(loginAction.getUsername());
//            if (p == null) {
//                client.sendActionEcho(new SimpleSystemAction(SimpleSystemAction.ActionType.userNotFound));
////                finalState = false;
//                return;
//            } else if (!p.getPassword().equals(loginAction.getPassword())) {
//                client.sendActionEcho(new SimpleSystemAction(SimpleSystemAction.ActionType.passwordIncorrect));
////                finalState = false;
//                return;
//            }
//            // uspesne prihlasen
//            client.setPlayer(p);

            // poslat seznam mistnosti
            Map<Long, Room> rooms = casino.getRooms();
            Map<Long, String> shortRooms = new HashMap<Long, String>();
            for (Long id : rooms.keySet()) {
                shortRooms.put(id, rooms.get(id).getId().toString());
            }
            client.sendMessage(new RoomListEcho(shortRooms));

            state = ClientState.online;
        } else if (state.equals(ClientState.online)) {
            if (rawAction instanceof CreateRoomAction) {
                CreateRoomAction createRoomAction = (CreateRoomAction) rawAction;
                // vytvarim pokoj
                log.debug("Vytvarim novou mistnost");
                currentRoom = casino.createRoom(new MariasFactory(), client);
                
                createRoomAction.setRoomId(currentRoom.getId());
                client.sendMessage(new SignedAction(createRoomAction));
                state = ClientState.sitting;
            } else if (rawAction instanceof ConnectRoomAction) {
                ConnectRoomAction connectRoomAction = (ConnectRoomAction) rawAction;

                Room room = casino.getRooms().get(connectRoomAction.getRoomId());
                int position = room.sitDown(client);
                if (position >= 0) {
                    // send sitting position
//                    client.sendActionEcho(connectRoomAction)
                    state = ClientState.sitting;
                } else {
                    // send full room
                }
            }
        } else if (state.equals(ClientState.sitting)) {
            // pokud se hraje, muze hrat, jinak se muze jen zvednout ze sveho mista

            // @TODO jen pro testovaci ucely
            if (currentRoom == null) {
                currentRoom = casino.createRoom(new MariasFactory(), client);
            }

            if (action.getRawAction() instanceof GameAction) {
                AbstractGame game = currentRoom.getCurrentGame();
                if (game != null) {
                    game.processAction(action);
                    if (game.isGameEnd()) {

                    }
                }
            }
        }
        // zpracovani akce od klienta - zkontrolovat, zmenit stav a pripadne vlozit do fronty pro game
    }

//    public boolean isFinalState() {
//        return finalState;
//    }

}
